﻿using AxMSTSCLib;
using MSTSCLib;
using System.Diagnostics;

namespace RdpClient.Forms
{


    public partial class FrmSession : Form
    {
        FrmMain FrmParent;

        public string SessionName = "";

        public string SessionServer = "";

        public int SessionPort = 3389;

        public string UserName = "";

        public string Password = "";

        public string IsShareDisk = "N";

        public Action FrmClose;

        public FrmSession(FrmMain frm)
        {
            InitializeComponent();
            FrmParent = frm;
            this.SizeChanged += Form_SizeChanged;


        }

        private void Form_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Maximized)
            {
                this.MdiParent = null;//不设父窗体
            }
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.MdiParent = FrmParent;//指定子窗体的父窗体
                //this.Parent = FrmParent.pnlSessions;//指定父容器
            }
        }

        private void FrmSession_Load(object sender, EventArgs e)
        {

            this.RdpInit();


        }

        private void RdpInit()
        {

            RdpInitRedirect();
            // 设置服务器地址
            rdpClient.Server = SessionServer;

            // （可选）设置用户名和域 
            rdpClient.Domain = "";
            rdpClient.UserName = UserName;
            rdpClient.AdvancedSettings2.RDPPort = SessionPort;
            MSTSCLib.IMsTscNonScriptable secured = (MSTSCLib.IMsTscNonScriptable)rdpClient.GetOcx();
            secured.ClearTextPassword = Password;
            rdpClient.AdvancedSettings2.ClearTextPassword = Password;
            rdpClient.FullScreenTitle = SessionName;

            rdpClient.ConnectingText = $"正在连接[{SessionName}]，请稍等... ";
            rdpClient.AdvancedSettings2.SmartSizing = true;//控件随窗体自适应变化
            rdpClient.AdvancedSettings9.NegotiateSecurityLayer = true;//安全检查
            rdpClient.ColorDepth = 32;//色彩位数


            rdpClient.OnRequestGoFullScreen += (sender, args) =>
            {
                Console.WriteLine("RDP Host:  OnRequestGoFullScreen");
                //OnGoToFullScreenRequested();
            };

            rdpClient.OnRequestLeaveFullScreen += (sender, args) =>
            {
                Console.WriteLine("RDP Host:  OnRequestLeaveFullScreen");
                //OnConnectionBarRestoreWindowCall();
            };
            rdpClient.OnRequestContainerMinimize += (sender, args) =>
            {
                Console.WriteLine("RDP Host:  OnRequestContainerMinimize");

            };

            //_rdpClient.OnConfirmClose += (sender, e) =>
            //{
            // invoke in the full screen mode.
            //Console.WriteLine("RDP Host:  RdpOnConfirmClose");
            //base.OnClosed?.Invoke(base.ConnectionId);
            //};

            rdpClient.OnConnected += RdpClient_OnConnected;
            rdpClient.OnDisconnected += RdpClient_OnDisconnected;

            rdpClient.OnLoginComplete += (sender, args) =>
            {
                Console.WriteLine("RDP Host:  OnLoginComplete");

            };
            //rdpClient.CreateControl();
            RdpInitStatic();
            RdpInitConnBar();

            // 设置远程桌面的宽度和高度
            rdpClient.DesktopWidth = pnlMain.Width;
            rdpClient.DesktopHeight = pnlMain.Height;


            // 连接到远程桌面
            rdpClient.Connect();

            //全屏显示
            //rdpClient.FullScreen = true;

        }

        private void pnlMain_SizeChanged(object sender, EventArgs e)
        {
            //rdpClient.Width = pnlMain.Width;
            //rdpClient.Height = pnlMain.Height;
            //rdpClient.Visible = false;
            //rdpClient.Reconnect((uint)rdpClient.Width, (uint)rdpClient.Height);
        }

        private void RdpClient_OnConnected(object? sender, EventArgs e)
        {
            //连接成功

        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RdpClient_OnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
        {
            MessageBox.Show("远程连接已断开");
            //断开连接
            this.Close();
        }

        private void RdpInitStatic()
        {
            Debug.Assert(rdpClient != null);
            rdpClient.AdvancedSettings7.EnableCredSspSupport = true;//指定是否为此连接启用凭据安全服务提供程序 (CredSSP) 。
            rdpClient.AdvancedSettings2.EncryptionEnabled = 1;
            rdpClient.AdvancedSettings5.AuthenticationLevel = 0;//指定要用于连接的身份验证级别。0,不对服务器进行身份验证  1,服务器身份验证是必需的，并且必须成功完成才能继续连接。  2,尝试对服务器进行身份验证。 如果身份验证失败，系统将提示用户取消连接或继续不进行服务器身份验证的选项。
            rdpClient.AdvancedSettings5.EnableAutoReconnect = true;//指定在网络断开连接时是否允许客户端控件自动重新连接到会话。 
            rdpClient.AdvancedSettings6.PublicMode = false;//设置或检索公共模式的配置。 公共模式阻止客户端将用户数据缓存到本地系统。
            rdpClient.AdvancedSettings5.EnableWindowsKey = 1;//指定是否可以在远程会话中使用Windows密钥。将此参数设置为 0 以禁用该功能或非零值以启用该功能。
            rdpClient.AdvancedSettings5.GrabFocusOnConnect = true;//指定客户端控件在连接时是否应具有焦点。 控件不会尝试从其他进程中运行的窗口中获取焦点。
            rdpClient.AdvancedSettings2.keepAliveInterval = 1000 * 60 * 1; // 指定客户端向服务器发送保持连接消息的时间间隔（以毫秒为单位）。
            rdpClient.AdvancedSettings2.overallConnectionTimeout = 600; // 指定客户端控件等待连接完成的总时间长度（以秒为单位）。最大值 600（10分钟）.
            rdpClient.AdvancedSettings7.ConnectToAdministerServer = true;//检索或指定ActiveX控件是否应尝试出于管理目的连接到服务器。
        }

        private void RdpInitConnBar()
        {
            Debug.Assert(rdpClient != null);
            rdpClient.AdvancedSettings6.DisplayConnectionBar = true;//指定是否使用连接栏。
            rdpClient.AdvancedSettings6.ConnectionBarShowPinButton = true;//设置或检索连接栏中的固定按钮的配置。
            rdpClient.AdvancedSettings6.PinConnectionBar = false;//指定 UI 连接栏的状态。
            rdpClient.AdvancedSettings6.ConnectionBarShowMinimizeButton = true;//指定是否在连接栏上显示 “最小化 ”按钮。
            rdpClient.AdvancedSettings6.ConnectionBarShowRestoreButton = true;//指定是否在连接栏上显示 “还原 ”按钮。
            rdpClient.AdvancedSettings6.BitmapVirtualCache32BppSize = 48;//设置或检索每个像素 32 位的虚拟缓存文件大小， (bpp) 位图。
        }

        private void RdpInitRedirect()
        {
            Debug.Assert(rdpClient != null);
            Console.WriteLine("RDP Host: init Redirect");


            #region Redirect

            // purpose is not clear
            ((IMsRdpClientNonScriptable3)rdpClient.GetOcx()).RedirectDynamicDrives = true;//指定或检索动态附加即插即用 (PnP) 在会话中枚举的驱动器是否可用于重定向。
            ((IMsRdpClientNonScriptable3)rdpClient.GetOcx()).RedirectDynamicDevices = true;//指定或检索在会话中枚举的动态附加即插即用 (PnP) 设备是否可用于重定向
            if (IsShareDisk == "Y" && rdpClient.AdvancedSettings9.RedirectDrives)  //指定是否允许重定向磁盘驱动器。
            {
                rdpClient.AdvancedSettings9.RedirectDrives = true;
                // disable disk
                if (rdpClient.AdvancedSettings9.RedirectDrives == false)
                {
                    var ocx = (MSTSCLib.IMsRdpClientNonScriptable7)rdpClient.GetOcx();
                    ocx.DriveCollection.RescanDrives(false);
                    for (int i = 0; i < ocx.DriveCollection.DriveCount; i++)
                    {
                        ocx.DriveCollection.DriveByIndex[(uint)i].RedirectionState = false;
                    }
                }
            }

            RedirectDevice();


            rdpClient.AdvancedSettings9.RedirectClipboard = true;//设置或检索剪贴板重定向的配置。
            rdpClient.AdvancedSettings9.RedirectPrinters = true;//指定是否允许重定向打印机。
            rdpClient.AdvancedSettings9.RedirectPOSDevices = true;//设置或检索服务点设备重定向的配置。
            rdpClient.AdvancedSettings9.RedirectSmartCards = true;//指定是否允许对智能卡进行重定向。 

            // - 0 Apply key combinations only locally at the client computer.
            // - 1 Apply key combinations at the remote server.
            // - 2 Apply key combinations to the remote server only when the client is running in full-screen mode. This is the default value.
            rdpClient.SecuredSettings3.KeyboardHookMode = 1; //指定键盘重定向设置，这些设置指定如何以及何时应用 Windows 键盘快捷方式 (例如 Alt+TAB) 。0,仅在客户端计算机上本地应用组合键。1,在远程服务器上应用组合键。2,仅当客户端以全屏模式运行时，才将组合键应用于远程服务器。 这是默认值。




            rdpClient.SecuredSettings3.AudioRedirectionMode = 0;//设置和检索音频重定向模式和不同的音频重定向选项。

            rdpClient.AdvancedSettings8.AudioCaptureRedirectionMode = true;//示是否将默认音频输入设备从客户端重定向到远程会话。

            #endregion Redirect
        }

        public void RedirectDevice()
        {
            var ocx = rdpClient?.GetOcx() as MSTSCLib.IMsRdpClientNonScriptable7;
            if (ocx == null)
                return;
            ocx.CameraRedirConfigCollection.RedirectByDefault = false;
            if (true)
            {
                // 获取 (相机的集合，以及可用于重定向的关联配置) 。
                ocx.CameraRedirConfigCollection.Rescan();
                for (int i = 0; i < ocx.CameraRedirConfigCollection.Count; i++)
                {
                    var camera = ocx.CameraRedirConfigCollection.ByIndex[(uint)i];
                    camera.Redirected = true;
                }
            }

            //检索要重定向即插即用(PnP) 设备对象的集合。以及可用于重定向的关联配置。
            ocx.DeviceCollection.RescanDevices(false);
            for (uint i = 0; i < ocx.DeviceCollection.DeviceCount; i++)
            {
                var d = ocx.DeviceCollection.DeviceByIndex[i];
                d.RedirectionState = true;
            }
        }

        /// <summary>
        /// 窗体关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FrmSession_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                //断开连接
                if (rdpClient != null)
                {
                    rdpClient.Disconnect();
                    rdpClient?.Dispose();
                }
            }
            catch (Exception ex)
            {

            }

            if (FrmClose != null)
            {
                FrmClose();
            }



        }
    }
}
